xquery version "1.0-ml";
module namespace my="my";
declare default function namespace "http://www.w3.org/2005/xpath-functions";
import module namespace ut="http://marklogic.com/test/unit" at "lib/unit-test.xqy";
import module namespace http-util="http://marklogic.com/util/http" at "../../../src/lib/http.xqy";
declare namespace http="xdmp:http";
declare namespace error="http://marklogic.com/xdmp/error";

declare function my:get-tests() as xs:QName* {
	for $test in (
		"test-preferred-variant-ie8",
		"test-preferred-variant-webkit",
		"test-preferred-variant-firefox",
		"test-string-to-variant",
		"test-preferred-variant-quality-order",
		"test-preferred-variant-quality",
		"test-preferred-variant-simple",
		"test-preferred-variant-wildcard-subtype",
		"test-preferred-variant-wildcard-both",
		"test-preferred-variant-wildcard-both-quality",
		"test-preferred-variant-wildcard-both-quality-lower",
		"test-preferred-variant-wildcard-mixed",
		"test-preferred-variant-none",
		"test-parse-accept-plus",
		"test-parse-headers",
		"test-parse-accept-simple",
		"test-parse-accept-many",
		"test-parse-accept-many-with-params",
		"test-parse-params",
		"test-parse-params-many",
		"test-parse-params-quality"
		) return QName("my", $test)
};


declare function my:test-parse-headers() {
	let $request as item()+ := http-util:parse-request()
	return (
		$request,
		(: TODO: Use mime-types to parse as XML :) 
		xdmp:get-request-body()
	)
};

declare function my:test-parse-accept-simple() {
	let $accept as xs:string := "application/xml"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(1, count($v/http:variant)),
		ut:assert-equals("application", data($v/http:variant[1]/http:media-type/http:type)),
		ut:assert-equals("xml", data($v/http:variant[1]/http:media-type/http:sub-type))
	)
};

declare function my:test-parse-accept-plus() {
	let $accept as xs:string := "application/atom+xml"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(1, count($v/http:variant)),
		ut:assert-equals("application", data($v/http:variant[1]/http:media-type/http:type)),
		ut:assert-equals("atom+xml", data($v/http:variant[1]/http:media-type/http:sub-type))
	)
};

declare function my:test-parse-accept-many() {
	let $accept as xs:string := "application/xml,   foo/bar	,	 baz/*"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(3, count($v/http:variant)),
		ut:assert-equals("application", data($v/http:variant[1]/http:media-type/http:type)),
		ut:assert-equals("xml", data($v/http:variant[1]/http:media-type/http:sub-type)),
		ut:assert-equals("foo", data($v/http:variant[2]/http:media-type/http:type)),
		ut:assert-equals("bar", data($v/http:variant[2]/http:media-type/http:sub-type)),
		ut:assert-equals("baz", data($v/http:variant[3]/http:media-type/http:type)),
		ut:assert-equals("*", data($v/http:variant[3]/http:media-type/http:sub-type))
	)
};

declare function my:test-parse-accept-many-with-params() {
	let $accept as xs:string := "application/xml;a=b,   foo/bar	; c = d ; q=1,	 baz/*"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(3, count($v/http:variant)),
		ut:assert-equals("application", data($v/http:variant[1]/http:media-type/http:type)),
		ut:assert-equals("xml", data($v/http:variant[1]/http:media-type/http:sub-type)),
		ut:assert-equals("foo", data($v/http:variant[2]/http:media-type/http:type)),
		ut:assert-equals("bar", data($v/http:variant[2]/http:media-type/http:sub-type)),
		ut:assert-equals("baz", data($v/http:variant[3]/http:media-type/http:type)),
		ut:assert-equals("*", data($v/http:variant[3]/http:media-type/http:sub-type))
	)
};

declare function my:test-parse-params() {
	let $accept as xs:string := "application/xml;charset=utf-8"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(1, count($v/http:variant)),
		ut:assert-equals("application", data($v/http:variant[1]/http:media-type/http:type)),
		ut:assert-equals("xml", data($v/http:variant[1]/http:media-type/http:sub-type)),
		ut:assert-equals(1, count($v/http:variant[1]/http:param)),
		ut:assert-equals("charset", data($v/http:variant[1]/http:param[1]/@name))
	)
};
declare function my:test-parse-params-many() {
	let $accept as xs:string := "application/xml;charset=utf-8;	     some=other      "
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(2, count($v/http:variant[1]/http:param), $v),
		ut:assert-equals("charset", data($v/http:variant[1]/http:param[1]/@name)),
		ut:assert-equals("some", data($v/http:variant[1]/http:param[2]/@name)),
		ut:assert-equals("other", data($v/http:variant[1]/http:param[2]))
	)
};
declare function my:test-parse-params-quality() {
	let $accept as xs:string := "application/xml;q=0.99"
	let $v := http-util:parse-accept-header($accept)
	return (
		ut:assert-equals(0.99, xs:float($v/http:variant[1]/http:quality))	
	)
};

declare function my:test-preferred-variant-simple() {
	let $accept as xs:string := "application/xml"
	let $request-variants := http-util:parse-accept-header($accept)
	let $preferred-variant := http-util:preferred-variant(
		$request-variants,
		(
			http-util:string-to-variant("application/xml"),
			http-util:string-to-variant("foo/bar")
		)
	)
	return (
		ut:assert-true(not(empty($preferred-variant))),
		ut:assert-equals(1, count($preferred-variant)),
		ut:assert-equals("application", $preferred-variant//http:type),
		ut:assert-equals("xml", $preferred-variant//http:sub-type)
	)
};

declare function my:test-preferred-variant-quality() {
	let $accept as xs:string := "application/xml,foo/bar;q=0.9"
	let $request-variants := http-util:parse-accept-header($accept)
	let $preferred-variant := http-util:preferred-variant(
		$request-variants,
		(
			http-util:string-to-variant("application/xml"),
			http-util:string-to-variant("foo/bar")
		)
	)
	return (
		ut:assert-true(not(empty($preferred-variant))),
		ut:assert-equals(1, count($preferred-variant)),
		ut:assert-equals("application", $preferred-variant//http:type),
		ut:assert-equals("xml", $preferred-variant//http:sub-type)
	)
};

declare function my:test-preferred-variant-quality-order() {
	let $accept as xs:string := "application/xml;q=0.7,foo/bar+baz;q=0.9;something=else"
	let $request-variants := http-util:parse-accept-header($accept)
	let $preferred-variant := http-util:preferred-variant(
		$request-variants,
		(
			http-util:string-to-variant("application/xml"),
			http-util:string-to-variant("foo/bar+baz")
		)
	)
	return (
		ut:assert-true(not(empty($preferred-variant))),
		ut:assert-equals(1, count($preferred-variant)),
		ut:assert-equals("foo", $preferred-variant//http:type),
		ut:assert-equals("bar+baz", $preferred-variant//http:sub-type)
	)
};

declare function my:test-string-to-variant() {
	let $string := "myspecial/type-here;foo=bar ;blah=baz;	yes=no"
	let $variants := http-util:string-to-variant($string)
	return (
		ut:assert-equals(1, count($variants)),
		ut:assert-equals("myspecial", $variants//http:type),
		ut:assert-equals("type-here", $variants//http:sub-type),
		ut:assert-equals(3, count($variants/http:param)),
		for $name at $i in ("foo","blah","yes")
		return ut:assert-equals($name, $variants/http:param[$i]/@name),
		for $name at $i in ("bar","baz","no")
		return ut:assert-equals($name, $variants/http:param[$i])
	)
};

(: This tests corrctness, but not desired outcomes :)
declare function my:test-preferred-variant-webkit() {
	let $request := http-util:parse-accept-header("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5")
	let $variants := (
		http-util:string-to-variant("application/xml"),
		http-util:string-to-variant("text/html"),
		http-util:string-to-variant("application/atom+xml;type=entry")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("application", $preferred/http:media-type/http:type),
		ut:assert-equals("xml", $preferred/http:media-type/http:sub-type)
	) 
};

declare function my:test-preferred-variant-firefox() {
	let $request := http-util:parse-accept-header("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	let $variants := (
		http-util:string-to-variant("application/xml"),
		http-util:string-to-variant("text/html"),
		http-util:string-to-variant("application/atom+xml;type=entry")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("text", $preferred/http:media-type/http:type),
		ut:assert-equals("html", $preferred/http:media-type/http:sub-type)
	) 
};



declare function my:test-preferred-variant-ie8() {
	let $request := http-util:parse-accept-header("image/jpeg, application/x-ms-application, image/gif,application/xaml+xml, image/pjpeg, application/x-ms-xbap,application/x-shockwave-flash, application/msword, */*")
	let $variants := (
		http-util:string-to-variant("text/html"),
		http-util:string-to-variant("application/xml"),
		http-util:string-to-variant("application/atom+xml;type=entry")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("text", $preferred/http:media-type/http:type),
		ut:assert-equals("html", $preferred/http:media-type/http:sub-type)
	) 
};

declare function my:test-preferred-variant-wildcard-subtype() {
	let $request := http-util:parse-accept-header("image/*,text/plain")
	let $variants := (
		http-util:string-to-variant("application/xml"),
		http-util:string-to-variant("application/atom+xml;type=entry"),
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("something/else")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("image", $preferred/http:media-type/http:type),
		ut:assert-equals("png", $preferred/http:media-type/http:sub-type)
	) 
};

declare function my:test-preferred-variant-wildcard-both() {
	let $request := http-util:parse-accept-header("*/*;q=0.9,text/plain")
	let $variants := (
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("application/xml"),
		http-util:string-to-variant("application/atom+xml;type=entry"),
		http-util:string-to-variant("something/else")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("image", $preferred/http:media-type/http:type),
		ut:assert-equals("png", $preferred/http:media-type/http:sub-type)
	) 
};
declare function my:test-preferred-variant-wildcard-both-quality() {
	let $request := http-util:parse-accept-header("*/*,text/plain;q=0.9")
	let $variants := (
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("text/plain")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("image", $preferred/http:media-type/http:type),
		ut:assert-equals("png", $preferred/http:media-type/http:sub-type)
	) 
};
declare function my:test-preferred-variant-wildcard-both-quality-lower() {
	let $request := http-util:parse-accept-header("*/*;q=0.9,text/plain")
	let $variants := (
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("text/plain")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("text", $preferred/http:media-type/http:type),
		ut:assert-equals("plain", $preferred/http:media-type/http:sub-type)
	) 
};
declare function my:test-preferred-variant-wildcard-mixed() {
	let $request := http-util:parse-accept-header("*/*,image/*")
	let $variants := (
		http-util:string-to-variant("asdf/asdf"),
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("text/plain")
	)
	let $preferred as element(http:variant) := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-equals("image", $preferred/http:media-type/http:type),
		ut:assert-equals("png", $preferred/http:media-type/http:sub-type)
	) 
};
declare function my:test-preferred-variant-none() {
	let $request := http-util:parse-accept-header("asdf/bbbbbb,wert/sdfg")
	let $variants := (
		http-util:string-to-variant("asdf/asdf"),
		http-util:string-to-variant("image/png"),
		http-util:string-to-variant("text/plain")
	)
	let $preferred as empty-sequence() := http-util:preferred-variant($request, $variants)
	return (
		ut:assert-true(empty($preferred))
	) 
};